/*
 *
 *  * Copyright (c) 2016. For Intelligent Group.
 *
 */

package com.intelligent.ispc.chart.grr;

import com.intelligent.ispc.common.utils.MathUtils;
import com.intelligent.ispc.foundation.chart.AbstractChart;
import com.intelligent.ispc.foundation.chart.axis.FixedNumberAxis;
import com.intelligent.ispc.foundation.chart.util.ChartColor;
import com.intelligent.ispc.foundation.chart.util.ChartUtil;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.IntervalMarker;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.Range;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.Layer;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;

import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by cherry on 2016/8/19.
 * Modified by QiangChen on 2016/11/7.
 */
public class XBarOrRChart extends AbstractChart {

    private IntervalXYDataset dataset;
    private JFreeChart localChart;
    private String chartType;
    private double[] sourceData;
    private double[] warningData;
    private double[] divideLines;
    private String[] xLabels;
    private int part;
    private String chartName;
    private boolean isDataValid;

    /**
     * @param value     The value in X Bar-Chart represents the average result of each person's test for each product and
     *                  the value in the R-Chart indicates that each person tested the result of the margin value for each product.
     * @param chartType is used to indicate whether X Bar-Chart or R-Chart.
     * @param part      indicates the type of the product.
     */
    public XBarOrRChart(double[] value, String chartType, int part) {
        this.isDataValid = true;
        this.chartName = chartType;
        this.part = part;
        this.sourceData = value;
        this.chartType = chartType;
        this.dataset = createDataset();
    }

    /*
    * Create dataset for XBarOrRChart, and the abnormal data is processed as necessary.
    * */
    private IntervalXYDataset createDataset() {

        final int warningDataLength = 3;
        if (sourceData == null) {
            isDataValid = false;
        } else {
            int j = 1;
            int size = sourceData.length / part;

            divideLines = new double[size + 1];
            warningData = new double[warningDataLength];
            xLabels = new String[size];
            divideLines[0] = 0D;

            double[] yValue = new double[sourceData.length - warningDataLength];

            for (int i = 0; i < size; i++) {
                xLabels[i] = "Operator" + (i + 1);
            }

            System.arraycopy(sourceData, 0, yValue, 0, sourceData.length - warningDataLength);
            System.arraycopy(sourceData, sourceData.length - warningDataLength, warningData, 0, warningDataLength);
            XYSeries localXYSeries = new XYSeries("");
            final double splitOffset = 1.5;
            for (int i = 0; i < yValue.length; i++) {
                if ((i + 1) % part == 0) {
                    divideLines[j] = i + splitOffset;
                    j++;
                }
                if (Double.isNaN(yValue[i])) {
                    continue;
                }
                localXYSeries.add(i + 1, yValue[i]);
            }
            XYSeriesCollection localXYSeriesCollection = new XYSeriesCollection(localXYSeries);
            return localXYSeriesCollection;
        }
        return null;
    }

    @Override
    protected JFreeChart buildChart() {

        if (!isDataValid) {
            return this.blankChart(chartName);
        }

        localChart = ChartFactory.createXYLineChart(chartType, "Operator", "", dataset, PlotOrientation.VERTICAL, false, true, false);
        XYPlot localXYPlot = (XYPlot) localChart.getPlot();

        NumberAxis yAxis = (NumberAxis) localXYPlot.getRangeAxis();
        final double upperMargin = 0.15;
        yAxis.setUpperMargin(upperMargin);

        NumberAxis xAxis = (NumberAxis) localXYPlot.getDomainAxis();
        xAxis.setVisible(true);

        yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        XYLineAndShapeRenderer localLineAndShapeRenderer = (XYLineAndShapeRenderer) localXYPlot.getRenderer();
        localLineAndShapeRenderer.setSeriesPaint(0, ChartColor.RED);
        localLineAndShapeRenderer.setBaseShapesVisible(true);
        localLineAndShapeRenderer.setDrawOutlines(true);
        localLineAndShapeRenderer.setUseFillPaint(true);
        localLineAndShapeRenderer.setBaseFillPaint(ChartColor.RED);
        localLineAndShapeRenderer.setSeriesStroke(0, new BasicStroke(1.0F));
        localLineAndShapeRenderer.setSeriesOutlineStroke(0, new BasicStroke(1.0F));
        final Ellipse2D ellipse2D = new Ellipse2D.Double(-2.0D, -2.0D, 4.0D, 4.0D);
        localLineAndShapeRenderer.setSeriesShape(0, ellipse2D);
        localLineAndShapeRenderer.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator());
        localLineAndShapeRenderer.setBaseItemLabelsVisible(false);
        localLineAndShapeRenderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator("{2}", new DecimalFormat(""), new DecimalFormat(this.getDigNumFormat())));

        FixedNumberAxis axis = new FixedNumberAxis();
        axis.setTickLabelInsets(new RectangleInsets(10, 0, 10, 0));

        List<Double> data = new ArrayList<Double>();

        for (int i = 0; i < sourceData.length; i++) {
            if (!Double.isNaN(sourceData[i])) {
                data.add(sourceData[i]);
            }
        }

        for (int j = 0; j < warningData.length; j++) {
            if (!Double.isNaN(warningData[j])) {
                data.add(warningData[j]);
            }
        }

        //The maximum and minimum values are calculated to limit the range of Y coordinates.
        double min = 0;
        double max = 0;

        if (data != null && data.size() != 0) {
            min = MathUtils.findMin(data);
            max = MathUtils.findMax(data);
        }

        if (max != min) {
            final double factor = 0.20;
            double reserve = (max - min) * factor;
            axis.setR(new Range(min - reserve, max + reserve));
            localXYPlot.setRangeAxis(axis);
        }

        FixedNumberAxis domainAxis = new FixedNumberAxis();
        domainAxis.setR(localXYPlot.getDomainAxis().getRange());
        domainAxis.setVisible(false);
        localXYPlot.setDomainAxis(domainAxis);

        for (int i = 0; i < divideLines.length - 1; i++) {
            IntervalMarker localIntervalMarker = new IntervalMarker(divideLines[i], divideLines[i + 1]);
            localIntervalMarker.setLabel(xLabels[i]);
            final float alpha = 0.6f;
            localIntervalMarker.setAlpha(alpha);
            final int fontSize = 11;
            localIntervalMarker.setLabelFont(new Font("SansSerif", 2, fontSize));
            localIntervalMarker.setLabelAnchor(RectangleAnchor.BOTTOM);
            localIntervalMarker.setLabelTextAnchor(TextAnchor.BOTTOM_CENTER);
            localIntervalMarker.setPaint(ChartColor.WHITE);
            localXYPlot.addDomainMarker(localIntervalMarker, Layer.BACKGROUND);
        }

        Color[] colors = new Color[]{ChartColor.RED, ChartColor.GRAYBLUE, ChartColor.RED};
        String[] lineTitles = new String[]{"ucl=", "c=", "lcl="};

        for (int i = 0; i < warningData.length; i++) {
            ValueMarker valuemarker = ChartUtil.drawWarningLines(warningData[i], lineTitles[i] + new DecimalFormat(this.getDigNumFormat()).format(warningData[i]), colors[i]);
            valuemarker.setStroke(new BasicStroke(1.0F));
            localXYPlot.addRangeMarker(valuemarker);
        }

        return localChart;
    }

    public IntervalXYDataset getDataset() {
        return dataset;
    }

    public double[] getSourceData() {
        return sourceData;
    }

    public JFreeChart getLocalChart() {
        return localChart;
    }
}
